#include <iostream>
#include <string.h>
#include <vector>
#include <cassert>
using std::cout;
using std::cin;
using std::endl;
using std::vector;
//using std::assert;

class String {
private:
    char* _pstr;

public:
    // 构造函数 & 析构函数
    String();
    String(const char* pstr);
    ~String();

    // 拷贝构造函数 & 赋值运算函数
    String(const String&);
    String(String&&);
    String &operator=(const String&);
    String &operator=(const char *);
    String &operator=(String && rhs);

    // 运算符重载
    String &operator+=(const String &);
    String &operator+=(const char *);

    char &operator[](std::size_t index);
    const char &operator[](std::size_t index) const;

    friend String operator+(const String &, const String &);
    friend String operator+(const String &, const char *);
    friend String operator+(const char *, const String &);

    friend bool operator==(const String &, const String &);
    friend bool operator!=(const String &, const String &);

    friend bool operator<(const String &, const String &);
    friend bool operator>(const String &, const String &);
    friend bool operator<=(const String &, const String &);
    friend bool operator>=(const String &, const String &);

    friend std::ostream &operator<<(std::ostream &os, const String &s);
    friend std::istream &operator>>(std::istream &is, String &s);

    // 成员函数
    bool empty() const;
    size_t size() const;
    const char* c_str() const;
    String& append(const String&);
    String& append(const char*);

};

// 默认构造函数
String::String()
    :_pstr(new char[1]()){      // 默认申请一个空间
    }

// 带参构造函数
String::String(const char* pstr)
    :_pstr(new char[strlen(pstr) + 1]()){
        strcpy(_pstr, pstr);    // 注意拷贝字符串
    }

// 析构函数
String::~String() {
//    delete _pstr;
    delete[] _pstr; // 释放整个内存块
}

// 拷贝构造函数（委托构造）
String::String(const String& rhs)
    :_pstr(new char[strlen(rhs._pstr) + 1]()){
        strcpy(_pstr, rhs._pstr);
    }

// 移动拷贝构造函数
// 为什么去掉const: 如果增加const，无法将源对象置空
// 为什么执行浅拷贝：移交对象的控制权
String::String(String&& rhs)
    :_pstr(rhs._pstr){
        rhs._pstr = nullptr;
    }

// 赋值运算符
// 为什么参数有引用: 形参和实参结合会调用拷贝构造函数，多次调用形成递归
// 为什么参数有cons：为了避免修改右操作数的数据，为了避免修改变量；
// 为什么返回时有引用：返回值为类型时会再次调用拷贝构造函数
String& String::operator=(const String& rhs){
    // 为什么rhs要写引用: 判断this是否为rhs的首地址
    if(this != &rhs){
        // 执行深拷贝
        char *temp = new char[strlen(rhs._pstr) + 1]();
        strcpy(temp, rhs._pstr);
        
        // 释放旧内存,步骤应该在执行深拷贝前面
        delete []_pstr;

//        _pstr = rhs._pstr;
        // 指向生成的新空间
        _pstr = temp;
    }

    // 返回引用
    return *this;
}

// 赋值运算符
String& String::operator=(const char *pstr){
//    // 直接走构造函数 + 拷贝构造函数, 可能会多调用一次
//    String temp(pstr);
//    *this = temp;
//    return *this;

    // 不需要自赋值判断
    if(pstr != nullptr){
        delete []_pstr;
        
        char* temp = new char[strlen(pstr) + 1]();
        strcpy(temp, pstr);
        
        _pstr = temp;
    }    
    return *this;

}

// 移动赋值运算符
String& String::operator=(String && rhs){
    // 理论上不需要自赋值判断，但在C++11后，move可以将左值变为右值
    if(this != &rhs){
        delete[] _pstr;
        _pstr = rhs._pstr;

//       rhs._pstr = nullptr;
        rhs._pstr = new char[1]();  // 保证源对象有效性，源对象rhs如果继续调用rhs.empty()，可以引发未定义行为
        rhs._pstr[0] = '\0';
    }
    return *this;
}

// 判断空字符串
bool String::empty() const {
    return _pstr == nullptr || _pstr[0] == '\0';    // 如果构造函数永不为空，可以省略第一个条件
//    return size() == 0;   // 可以
//    return strlen(_pstr) == 0;    // 不可以，_pstr可能为空
}

// 获取字符串长度
size_t String::size() const {
    if(_pstr != nullptr){
        return strlen(_pstr);
    }
    else{
        return 0;
    }
}

// 获取C风格字符串
const char* String::c_str() const {
    return _pstr;
}

// 追加String对象
String& String::append(const String& rhs) {
    char* temp = new char[strlen(_pstr) + strlen(rhs._pstr) + 1]();
    strcpy(temp, _pstr);
    strcat(temp, rhs._pstr);

    delete[]_pstr;
    _pstr = temp;

    return *this;
}

// 追加C风格字符串
String& String::append(const char* pstr) {
    String temp(pstr);
    return this->append(temp);
}

String& String::operator+=(const String & rhs){
    return this->append(rhs);
}

String& String::operator+=(const char *pstr){
    return this->append(pstr);
}

String operator+(const String &lhs, const String &rhs){
    String temp(lhs);
    return temp.append(rhs);
}

String operator+(const String &lhs, const char *rhs){
    String temp(lhs);
    return temp.append(rhs);
}

String operator+(const char *lhs, const String &rhs){
    String temp(lhs);
    return temp.append(rhs);
}

char& String::operator[](std::size_t index){
    return _pstr[index];
}

const char& String::operator[](std::size_t index) const{
    return _pstr[index];
}

bool operator==(const String &lhs, const String &rhs){
//    return lhs == rhs;    // 递归了哥们
    return strcmp(lhs._pstr, rhs._pstr) == 0;
}

bool operator!=(const String &lhs, const String &rhs){
    return strcmp(lhs._pstr, rhs._pstr) != 0;
}

bool operator<(const String &lhs, const String &rhs){
    return strcmp(lhs._pstr, rhs._pstr) < 0;
}

bool operator>(const String &lhs, const String &rhs){
    return strcmp(lhs._pstr, rhs._pstr) > 0;
}

bool operator<=(const String &lhs, const String &rhs){
    return strcmp(lhs._pstr, rhs._pstr) < 0 || strcmp(lhs._pstr, rhs._pstr) == 0;
}

bool operator>=(const String &lhs, const String &rhs){
    return strcmp(lhs._pstr, rhs._pstr) > 0 || strcmp(lhs._pstr, rhs._pstr) == 0;
}

std::ostream &operator<<(std::ostream &os, const String &s){
    os << s._pstr;
    return os;
}

// 应当考虑的点：
// 1. 不可以直接使用is >> s._pstr，指针变量使用前必须初始化
// 2. 如果之前的s._pstr指向了某个对空间，那么还需要考虑是否会有内存泄漏
// 3. 首先判断当前指针是否指向了有效位置，如果有则回收该空间
// 4. 使用vector接收用户录入的字符数据（不确定用户究竟录入多少字符）
// 5. 申请堆空间，将vector里面的字符复制到堆空间中
// 6. 指针再去指向该堆空间
std::istream &operator>>(std::istream &is, String &s){
    if(s._pstr){
        delete[] s._pstr;
    }

    vector<char> _input;
//    char c;
//    while(c = is.get()){
//        if(c == '\n') break;

//    int c;
//    while(((c = is.get()) != EOF && c != '\n')){
//        _input.push_back(c);
//    }
//
    char c;
    while(true){
        c = is.get();
        if(c == '\n') break;
        _input.push_back(c);
    }

    s._pstr = new char[_input.size() + 1]();
//    strcpy(s._pstr, _input);
//    memcpy(_input.begin(), _input.end(), s._pstr);
    memcpy(s._pstr, _input.data(), _input.size());  // 修正 memcpy

    return is;
}

void test(){
    // ==================== 基础功能测试 ====================
    cout << "----- 测试1：构造与空状态 -----" << endl;
    String s1;  // 默认构造
    assert(s1.empty() && "默认构造应为空");
    assert(s1.size() == 0 && "默认构造长度应为0");
    cout << "s1: \"" << s1 << "\" (预期: \"\")" << endl;

    // ==================== 字符串构造测试 ====================
    cout << "\n----- 测试2：C字符串构造 -----" << endl;
    String s2("Hello");
    assert(!s2.empty() && "非空字符串不应为空");
    assert(s2.size() == 5 && "长度应为5");
    cout << "s2: \"" << s2 << "\" (预期: \"Hello\")" << endl;

    // ==================== 拷贝语义测试 ====================
    cout << "\n----- 测试3：拷贝构造 -----" << endl;
    String s3(s2);  // 拷贝构造
    assert(s3 == s2 && "拷贝构造应与原对象相同");
    s3[0] = 'h';    // 测试深拷贝
    assert(s2[0] == 'H' && "深拷贝修改不应影响原对象");
    cout << "s3修改后: \"" << s3 << "\" (s2应保持原样: \"" << s2 << "\")" << endl;

    // ==================== 赋值语义测试 ====================
    cout << "\n----- 测试4：赋值运算符 -----" << endl;
    String s4;
    s4 = s2;  // 赋值运算
    assert(s4 == s2 && "赋值后应与原对象相同");
    s4[4] = '!';
    assert(s2[4] == 'o' && "深拷贝修改不应影响原对象");
    cout << "s4修改后: \"" << s4 << "\" (s2应保持原样: \"" << s2 << "\")" << endl;

    // ==================== 移动语义测试 ====================
    cout << "\n----- 测试5：移动语义 -----" << endl;
    String s5 = std::move(String("Move"));  // 移动构造
    assert(s5 == "Move" && "移动构造应保留值");
    cout << "s5(移动构造): \"" << s5 << "\"" << endl;

    String s6;
    s6 = std::move(s5);  // 移动赋值
    assert(s5.empty() && "移动后源对象应为空");
    assert(s6 == "Move" && "移动赋值应保留值");
    cout << "s6(移动赋值): \"" << s6 << "\", s5应为空: \"" << s5 << "\"" << endl;

    // ==================== 字符串操作测试 ====================
    cout << "\n----- 测试6：字符串操作 -----" << endl;
    String s7("Hello");
    s7.append(" World");
    assert(s7 == "Hello World" && "append应正确拼接");
    cout << "s7.append: \"" << s7 << "\"" << endl;

    s7 += "!";
    assert(s7 == "Hello World!" && "+=应正确拼接");
    cout << "s7+=: \"" << s7 << "\"" << endl;

    // ==================== 运算符重载测试 ====================
    cout << "\n----- 测试7：运算符重载 -----" << endl;
    String s8 = "apple";
    String s9 = "banana";
    String s10 = "apple";

    // 比较运算符
    assert((s8 < s9) && "apple应小于banana");
    assert((s8 == s10) && "相同字符串应相等");
    assert((s8 != s9) && "不同字符串应不等");
    cout << "比较测试通过: " << s8 << " vs " << s9 << endl;

    // 下标访问
    s8[0] = 'A';
    assert(s8 == "Apple" && "下标修改应生效");
    cout << "s8[0]='A': \"" << s8 << "\"" << endl;

    // ==================== 边界情况测试 ====================
    cout << "\n----- 测试8：边界情况 -----" << endl;
    // 空字符串操作
    String s11;
    s11 += "non-empty";
    assert(!s11.empty() && "+=应处理空字符串");
    cout << "空字符串+=: \"" << s11 << "\"" << endl;

    // 自赋值
    String s12("self");
    s12 = s12;
    assert(s12 == "self" && "自赋值应安全处理");
    cout << "自赋值后: \"" << s12 << "\"" << endl;

    // 链式调用
    String s13("Start");
    s13.append(" middle").append(" end");
    assert(s13 == "Start middle end" && "链式调用应正确工作");
    cout << "链式调用: \"" << s13 << "\"" << endl;

    // ==================== 流操作测试 ====================
    cout << "\n----- 测试9：流操作 -----" << endl;
    String s14;
    cout << "请输入测试字符串: ";
    cin >> s14;
    cout << "你输入的是: \"" << s14 << "\" (长度: " << s14.size() << ")" << endl;

    // ==================== 复合测试 ====================
    cout << "\n----- 测试10：复合操作 -----" << endl;
    String s15 = "The answer is " + String("42");
    assert(s15 == "The answer is 42" && "+运算符应正确工作");
    cout << "字符串相加: \"" << s15 << "\"" << endl;

    cout << "\n===== 所有测试通过 =====" << endl;
}

int main() {
    test();
    return 0;
}

